package algorithm.poj.p1000;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;

/**
 * 分析：
 * 无向完全图的最小生成树，这里用Kruskal算法
 * 
 * 实现：
 * 
 * 经验：
 * 问题难度不大，但容易TLE和MLE!!!
 * 
 * 教训：
 * 
 * @author wong.tong@gmail.com
 *
 */
public class P1789 {

	@SuppressWarnings("unchecked")
	public static void main(String[] args) throws Exception {

//		long start = System.currentTimeMillis();
		InputStream input = null;
		if (false) {
			input = System.in;
		} else {
			URL url = P1789.class.getResource("P1789.txt");
			File file = new File(URLDecoder.decode(url.getPath(), "UTF-8"));
			input = new FileInputStream(file);
		}
		
		BufferedReader stdin = new BufferedReader(new InputStreamReader(input));

		String line = stdin.readLine();
		while (line != null && !"0".equals(line)) {
			int N = Integer.valueOf(line);
			Vertex[] vs = new Vertex[N];
			List<Edge>[] edges = new List[8];
			for (int i = 0; i < 8; i ++) {
				edges[i] = new ArrayList<Edge>();
			}
			for (short i = 0; i < N; i ++) {
				line = stdin.readLine();
				vs[i] = new Vertex(line.toCharArray());
				for (short j = 0; j < i; j ++) {
					short length = 0;
					for (int k = 0; k < 7; k ++) {
						if (vs[i].label[k] != vs[j].label[k]) length ++;
					}
					edges[length].add(new Edge(j, i));
				}
			}
			int min = 0;
			for (int i = 1; i < 8; i ++) {
				for (Edge edge: edges[i]) {
					Vertex u = vs[edge.u];
					Vertex v = vs[edge.v];
					if (!UnionSearch.find(u).equals(UnionSearch.find(v))) {
						min += i;
						UnionSearch.union(u, v);
					}
				}
			}
			
			System.out.println("The highest possible quality is 1/" + min + ".");
			line = stdin.readLine();
		}
	}
	
	private static class Vertex {
		
		private char[] label;
		private Vertex parent;
		private int rank;
		
		public Vertex(char[] label) {
			this.label = label;
			this.parent = this;
			this.rank = 0;
		}
		
		public boolean equals(Object o) {
			
			if (o == null || !(o instanceof Vertex)) {
				return false;
			} else {
				Vertex v = (Vertex)o;
				for (int i = 0; i < 7; i ++) {
					if (v.label[i] != this.label[i]) return false;
				}
				return true;
			}
		}
	}
	
	private static class Edge {
		
		private short u;
		private short v;

		public Edge(short u, short v) {
			this.u = u;
			this.v = v;
		}
	}

	private static class UnionSearch {

		public static Vertex find(Vertex x) {
			
			if (x != x.parent) {
				x.parent = find(x.parent);
			}
			return x.parent;
		}
		
		public static void union(Vertex x, Vertex y) {
			
			link(find(x), find(y));
		}
		
		private static void link(Vertex x, Vertex y) {
			
			if (x.rank > y.rank) {
				y.parent = x;
			} else {
				x.parent = y;
				if (x.rank == y.rank) {
					y.rank ++;
				}
			}
		}
	}
}